﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufArrangementAreaContent.h"
#include "GnufItemDeclaration.h"
#include "GnufIToolbarWatcher.h"
#include "GnufModuleManager.h"

namespace gnuf {
    class Item;
    class Toolbar;
    class ButtonEx;
    class ToolButton;
    class ButtonControl;
    class QtToolbar;
    class Preferences;
    class ScaleFactorChangedArrangementAreaEvent;
    class PreferencesChangedAreaEvent;
    class ConfigurationInfo;

    class GNUF_BASE_EXPORT Component
        : public ArrangementAreaContent
        , public IToolbarWatcher
    {
        DEFINE_CAST_DERIVED(Component, ArrangementAreaContent)
    protected:
        explicit Component(
            const std::wstring & key, 
            const std::wstring & config,
            bool configureByfile = true);

        explicit Component(
            const std::wstring & key,
            const gcmp::UniqueString * uniqueKey,
            const std::wstring & config,
            bool configureByfile = true);

        virtual ~Component();

    public:
        const gcmp::UniqueString * uniqueKey() const { return m_uniqueKey; }

        void setVisible(bool);
        bool visible() const;
        const Toolbar * rawToolbar() const { return m_toolbar.get(); }
        Toolbar * rawToolbar() { return m_toolbar.get(); }

        void dumpFromConfigString() ;

        /// \brief Hide and then show another sibling, silently.
        void hideAndThenShowSilently(Component * pSibling);

        /// \brief Attach me as a guest onto the host. 
        void attachOnto(Component * pHost);
        /// \brief Detach me as a guest from the host.
        void detachFrom(Component * pHost);

        /// \brief Dispose this component.
        void dispose();

    protected:
        // Inherits from ArrangementAreaContent...
        virtual QWidget * qtWidget() override;
        virtual void onPostVisibilityChanged() override;
        virtual void onPostConnectedWithArrangementArea() override;
        virtual void onPostReconnectedWithArrangementArea() override;
        virtual void onPreDisconnectedFromArrangementArea() override;
        virtual void onPostGeometryChanged() override;
        virtual void onEvent(ArrangementAreaEvent*) override;

        // Inherits from IToolbarWatcher...
        virtual void onAdded(const std::wstring &, ButtonEx *) const override;

        // Give the derived class an opportunity to initialize.
        virtual void initialize(Toolbar *) = 0;
        virtual gcmp::OwnerPtr<QtToolbar> createQtToolBar(Toolbar *) = 0;
        virtual void onPostToolbarCreated() {}
        typedef std::vector< Component * > Ones;
        virtual bool hasSiblings(Component::Ones * pVec = nullptr) const { return false; }
        virtual void onPostSiblingVisibilityChanged(const bool visible) {}
        virtual ETransferingContentMethod decideTransferringContentMethod(
            const Item * pSender, const Item * pAcceptor, const Item * pContent) const
        { return ETransferingContentMethod::eIgnore; }
        virtual void onPostDumpFromConfigString() {}

        // Create/Delete the toolbar.
        void createToolbar(bool isRelativePath);
        void deleteToolbar();

        // Return first type of item.
        const Item * searchItem(const EItemType, 
            const std::function<bool(const Item *)> & callback = nullptr) const;
        Item * searchItem(const EItemType,
            const std::function<bool(const Item *)> & callback = nullptr);

        void showBalloon(const Item *, bool, void *);

        const std::wstring & toolbarConfiguration() const { return m_toolbarConfiguration; }
        ArrangementArea * relatedArrangementArea() const;

        virtual void onButtonAdded(ButtonControl*, const std::wstring&, ButtonEx*) const;

        bool onHoveredForTooltip(const Item *, bool hovered, void * pQtWgt) const;
        void hideTooltip();

    private:
        template <typename TEvt> void siblingsHandle(const TEvt * pEvt);
        void handle(const ScaleFactorChangedArrangementAreaEvent *);
        void handle(const PreferencesChangedAreaEvent *);

        const gcmp::UniqueString * m_uniqueKey;
        const std::wstring m_toolbarConfiguration;
        gcmp::OwnerPtr<Toolbar> m_toolbar;
        gcmp::OwnerPtr<QtToolbar> m_qtToolbar;
        bool m_configureByFile;
    };
    
}

template <typename TEvt>
void gnuf::Component::siblingsHandle(const TEvt * pEvt)
{
    Component::Ones ones;
    if (hasSiblings(&ones)) {
        for (auto * one : ones)
            one->handle(pEvt);
    }
}
